package com.meatball.core.config

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.core.MethodParameter
import org.springframework.http.MediaType
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.http.server.ServerHttpRequest
import org.springframework.http.server.ServerHttpResponse
import org.springframework.lang.Nullable
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice

/**
 * 响应拦截器，这只全局返回
 * @author 张翔宇
 * @since 2023年3月16日
 * @version 1.0
 */
@RestControllerAdvice(basePackages = ["com.meatball"])
class BaseResponseBodyAdvice : ResponseBodyAdvice<Any?> {
    override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean {
        return true
        // 判断是否为文档，如果是文档则不拦截
//        val methodName = returnType.method?.name
//        return "openapiJson" != methodName
    }

    override fun beforeBodyWrite(
        @Nullable body: Any?,
        returnType: MethodParameter,
        selectedContentType: MediaType,
        selectedConverterType: Class<out HttpMessageConverter<*>>,
        request: ServerHttpRequest,
        response: ServerHttpResponse
    ): Any? {
        // 遇到feign接口之类的请求, 不应该再次包装,应该直接返回
        // 上述问题的解决方案: 可以在feign拦截器中,给feign请求头中添加一个标识字段, 表示是feign请求
        // 在此处拦截到feign标识字段, 则直接放行 返回body.
        return body as? BaseResponse
            ?: if (body == null) {
                BaseResponse.ok()
            } else if (body is String) {
                val om = ObjectMapper()
                om.writeValueAsString(BaseResponse.ok(body))
            } else {
                BaseResponse.ok(body)
            }
    }
}
